import hashlib
import json
import random
import time
from functools import wraps

import jwt
from django.core.cache import cache
from django.db.models import Q
from django.http import JsonResponse

# Create your views here.
from django.utils import timezone

from apps.user.models import UserInfo, LeaveWordInfo
from django.conf import settings
from .tasks import send_sms_c


# 检测请求方式的装饰器
def check_method(func):
    @wraps(func)
    def is_post(request):
        if request.method != 'POST':
            result = {'code': 401, 'error': '请求方式错误！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        else:
            # 取出请求的body体并把json格式转为python字典形式
            json_obj = json.loads(request.body)
            return func(request, json_obj)

    return is_post


# 生成有效期3天的令牌
def make_token(user_name, expire=3600 * 24 * 3):
    key = settings.JWT_TOKEN_KEY
    now_t = time.time()
    payload_data = {'user_name': user_name, 'exp': now_t + expire}
    return jwt.encode(payload_data, key, algorithm='HS256')


# 用户注册
@check_method
def register_view(request, json_obj):
    # 取出请求体中的数据若前端变量名错误等会给予报错信息
    try:
        is_management = json_obj['isManagement']
        user_sms_code = eval(json_obj['userSmsCode'])
        user_name = json_obj['userName']
        phone = json_obj['phone']
        password = json_obj['password']
        step = json_obj['step']
        real_name = json_obj['realName']
        email = json_obj['email']
        sex = json_obj['sex']
        user_nation = json_obj['userNation']
        user_number = json_obj['userNumber']
        user_status = json_obj['userStatus']
        user_school = json_obj['userSchool']
        user_school_id = json_obj['userSchoolId']
        qq_number = json_obj['qqNumber']
        user_occupation = json_obj['userOccupation']
        user_edu_background = json_obj['userEduBackground']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    # 第一步注册
    if step == 1:
        try:
            UserInfo.objects.get(Q(phone=phone) | Q(user_name=user_name))
            result = {'code': 403, 'error': '用户名或手机号已存在！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        except Exception as e:
            print(e)

        cache_key = 'sms_%s' % (phone)
        older_code = cache.get(cache_key)
        if older_code == user_sms_code:
            # 密码使用用md5加密
            # 加盐处理
            salt = settings.PASSWORD_SALT
            p_m = hashlib.md5()
            p_m.update((password + salt).encode())

            # 判定是否为管理员
            if is_management:
                inviationCode = json_obj['inviationCode']

                if inviationCode == 'GVolunteer2022110':
                    user_obj = UserInfo(user_name=user_name, phone=phone, password=p_m.hexdigest(), is_management=True)
                else:
                    result = {'code': 403, 'error': '邀请码错误！'}
                    return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
            else:
                user_obj = UserInfo(user_name=user_name, phone=phone, password=p_m.hexdigest())
            user_obj.save()

            result = {'code': 200, 'success': '第一步注册成功！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        else:
            result = {'code': 403, 'error': '验证码过期或错误！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    # 第二步注册
    elif step == 2:
        try:
            UserInfo.objects.get(email=email)

            result = {'code': 403, 'error': '该邮箱已被注册！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        except Exception as e:
            print(e)

        try:
            UserInfo.objects.get(user_number=user_number)
            result = {'code': 403, 'error': '该证件号已被注册！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        except Exception as e:
            print(e)

        age = json_obj['age']
        user_obj = UserInfo.objects.get(Q(phone=phone) | Q(user_name=user_name))
        user_obj.real_name = real_name
        user_obj.age = age
        user_obj.email = email
        user_obj.sex = sex
        user_obj.user_number = user_number
        user_obj.user_nation = user_nation
        user_obj.user_status = user_status
        user_obj.user_school = user_school
        user_obj.user_school_id = user_school_id
        user_obj.qq_number = qq_number
        user_obj.user_occupation = user_occupation
        user_obj.user_edu_background = user_edu_background
        user_obj.save()

        result = {'code': 200, 'success': '注册成功！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    else:
        result = {'code': 402, 'error': '步骤错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 用户登录
@check_method
def login_view(request, json_obj):
    try:
        user_name = json_obj['userName']
        password = json_obj['password']
        auto_login = json_obj['autoLogin']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    # 密码使用用md5加密
    # 加盐处理
    salt = settings.PASSWORD_SALT
    p_m = hashlib.md5()
    p_m.update((password + salt).encode())

    try:
        user_obj = UserInfo.objects.get(Q(phone=user_name) | Q(user_name=user_name))
        if p_m.hexdigest() == user_obj.password:
            if auto_login:
                token = make_token(user_name)
                user_info = {'avatar': str(user_obj.avatar),
                             'nickName': user_obj.nick_name,
                             'userName': user_obj.user_name,
                             'isManagement': user_obj.is_management
                             }

                result = {'code': 200, 'data': {'token': token, 'userInfo': user_info}, 'success': '登陆成功！'}
                return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
            else:
                user_info = {'avatar': str(user_obj.avatar),
                             'nickName': user_obj.nick_name,
                             'userName': user_obj.user_name,
                             'isManagement': user_obj.is_management
                             }

                result = {'code': 200, 'data': {'userInfo': user_info}, 'success': '登陆成功！'}
                return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        else:
            result = {'code': 403, 'error': '密码错误！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    except Exception as e:
        print(e)
        result = {'code': 403, 'error': '用户名不存在！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 自动登录
@check_method
def auto_login_view(request, json_obj):
    try:
        token = json_obj['token']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    if token != '':
        try:
            active_user = jwt.decode(token, settings.JWT_TOKEN_KEY, algorithms='HS256')
            user_name = active_user['user_name']
            user_obj = UserInfo.objects.get(Q(user_name=user_name) | Q(phone=user_name))

            user_info = {'avatar': str(user_obj.avatar),
                         'nickName': user_obj.nick_name,
                         'userName': user_obj.user_name,
                         'isManagement': user_obj.is_management
                         }

            result = {'code': 200, 'data': {'userInfo': user_info}, 'success': '登陆成功！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        except Exception as e:
            print(e)
            result = {'code': 403, 'error': '令牌过期或伪造令牌！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    else:
        result = {'code': 403, 'error': '请前往登录！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 修改密码
@check_method
def change_password_view(request, json_obj):
    try:
        user_sms_code = eval(json_obj['userSmsCode'])
        phone = json_obj['phone']
        password = json_obj['password']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    cache_key = 'sms_%s' % (phone)
    older_code = cache.get(cache_key)
    if older_code == user_sms_code:
        # 密码使用用md5加密
        # 加盐处理
        salt = settings.PASSWORD_SALT
        p_m = hashlib.md5()
        p_m.update((password + salt).encode())

        try:
            user_obj = UserInfo.objects.get(phone=phone)
            user_obj.password = p_m.hexdigest()
            user_obj.save()

            result = {'code': 200, 'success': '修改成功！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        except Exception as e:
            print(e)
            result = {'code': 403, 'error': '手机号错误或用户不存在！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    else:
        result = {'code': 403, 'error': '验证码过期或错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 发送验证码
@check_method
def send_sms(request, json_obj):
    try:
        phone = json_obj['phone']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    # 生成随机验证码
    code = random.randint(100000, 999999)

    # 存储随机验证码
    cache_key = 'sms_%s' % (phone)
    # 试取尚未过期的验证码
    older_code = cache.get(cache_key)
    if older_code:
        result = {'code': 403, 'error': '验证码已存在！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    else:
        cache.set(cache_key, code, 60)
        # 使用Celery的worker发送短信
        send_sms_c.delay(phone, code)
        # send_sms_c(phone, code)
        result = {'code': 200, 'success': '验证码发送成功！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 获取个人信息
@check_method
def get_userinfo(request, json_obj):
    try:
        user_name = json_obj['userName']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    try:
        user_obj = UserInfo.objects.get(user_name=user_name)
        data = user_obj.__dict__
        del data['_state']
        del data['password']

        result = {'code': 200, 'data': data}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    except Exception as e:
        print(e)
        result = {'code': 403, 'error': '用户不存在！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 修改个人信息
def modify_info(request):
    try:
        json_obj = json.loads(request.POST['data'])
        is_null = json_obj['isNull']
        user_name = json_obj['userName']
        real_name = json_obj['realName']
        nick_name = json_obj['nickName']
        email = json_obj['email']
        sex = json_obj['sex']
        user_nation = json_obj['userNation']
        user_number = json_obj['userNumber']
        user_status = json_obj['userStatus']
        user_school = json_obj['userSchool']
        user_school_id = json_obj['userSchoolId']
        qq_number = json_obj['qqNumber']
        user_occupation = json_obj['userOccupation']
        user_edu_background = json_obj['userEduBackground']
        user_intro = json_obj['userIntro']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    try:
        user_obj = UserInfo.objects.get(user_name=user_name)
        # 判断是否携带头像文件
        if not is_null:
            file = request.FILES['avatar']
            file.name = f'{timezone.now()} + {user_obj.phone}.jpg'
            user_obj.avatar = file

        user_obj.real_name = real_name
        user_obj.email = email
        user_obj.sex = sex
        user_obj.user_number = user_number
        user_obj.user_nation = user_nation
        user_obj.user_status = user_status
        user_obj.user_school = user_school
        user_obj.user_school_id = user_school_id
        user_obj.qq_number = qq_number
        user_obj.user_occupation = user_occupation
        user_obj.user_edu_background = user_edu_background
        user_obj.user_intro = user_intro
        user_obj.nick_name = nick_name
        user_obj.save()

        result = {'code': 200, 'avatar': user_obj.avatar.__str__()}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    except Exception as e:
        print(e)
        result = {'code': 403, 'error': '用户不存在！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 修改手机号
@check_method
def change_phone(request, json_obj):
    try:
        old_phone = json_obj['oldPhone']
        new_phone = json_obj['newPhone']
        user_sms_code = eval(json_obj['userSmsCode'])

        cache_key = 'sms_%s' % (old_phone)
        older_code = cache.get(cache_key)

        if older_code == user_sms_code:
            try:
                user_obj = UserInfo.objects.get(phone=old_phone)
                user_obj.phone = new_phone
                user_obj.save()

                result = {'code': 200, 'success': '修改成功！'}
                return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
            except Exception as e:
                print(e)
                result = {'code': 403, 'error': '手机号错误或用户不存在！'}
                return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
        else:
            result = {'code': 403, 'error': '验证码过期或错误！'}
            return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 编写留言板
@check_method
def create_leave_word(request, json_obj):
    try:
        user_name = json_obj['sender']
        leave_word_content = json_obj['leave_word_content']
    except Exception as e:
        print(e)
        result = {'code': 402, 'error': '未获取到数据或数据变量名错误！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )

    try:
        user_obj = UserInfo.objects.get(user_name=user_name)

        leave_word_obj = LeaveWordInfo(sender=user_obj, leave_word_content=leave_word_content)
        leave_word_obj.save()

        result = {'code': 200}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    except Exception as e:
        print(e)
        result = {'code': 403, 'error': '用户不存在！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )


# 首页展示留言板

def index_leave_word(request):
    leave_word_list = list(LeaveWordInfo.objects.all().order_by('-leave_word_create_time').values())
    data = []

    if len(leave_word_list) == 0:
        result = {'code': 403, 'error': '留言板为空！'}
        return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
    elif len(leave_word_list) < 5:
        for i in leave_word_list:
            user_obj = UserInfo.objects.get(id=i['sender_id']).__dict__
            del user_obj['_state']
            del user_obj['password']

            i['sender_info'] = user_obj
            data.append(i)
    else:
        for i in range(0, 5):
            user_obj = UserInfo.objects.get(id=leave_word_list[i]['sender_id']).__dict__
            del user_obj['_state']
            del user_obj['password']

            leave_word_list[i]['sender_info'] = user_obj
            data.append(leave_word_list[i])

    result = {'code': 200, 'data': data}
    return JsonResponse(result, json_dumps_params={"ensure_ascii": False}, )
